package com.agricultural.machine.logging;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 日志记录器类
 */
public class Logger {
    private static Logger instance;
    private final BlockingQueue<LogEntry> logQueue;
    private final DateTimeFormatter formatter;
    private final String logFilePath;
    private final Thread logWriterThread;
    private volatile boolean running;
    private LogLevel currentLevel;
    
    private Logger() {
        this.logQueue = new LinkedBlockingQueue<>();
        this.formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        this.logFilePath = "system_logs.txt";
        this.running = true;
        this.currentLevel = LogLevel.INFO; // 默认日志级别
        
        // 创建日志写入线程
        this.logWriterThread = new Thread(this::processLogQueue);
        this.logWriterThread.setDaemon(true);
        this.logWriterThread.start();
    }
    
    public static synchronized Logger getInstance() {
        if (instance == null) {
            instance = new Logger();
        }
        return instance;
    }
    
    /**
     * 设置日志级别
     */
    public void setLogLevel(LogLevel level) {
        this.currentLevel = level;
        log(LogLevel.INFO, "Logger", "日志级别已设置为: " + level.getDescription());
    }
    
    /**
     * 记录调试日志
     */
    public void debug(String source, String message) {
        log(LogLevel.DEBUG, source, message);
    }
    
    /**
     * 记录信息日志
     */
    public void info(String source, String message) {
        log(LogLevel.INFO, source, message);
    }
    
    /**
     * 记录警告日志
     */
    public void warning(String source, String message) {
        log(LogLevel.WARNING, source, message);
    }
    
    /**
     * 记录错误日志
     */
    public void error(String source, String message) {
        log(LogLevel.ERROR, source, message);
    }
    
    /**
     * 记录严重错误日志
     */
    public void critical(String source, String message) {
        log(LogLevel.CRITICAL, source, message);
    }
    
    /**
     * 记录异常日志
     */
    public void exception(String source, Exception e) {
        String stackTrace = getStackTraceAsString(e);
        log(LogLevel.ERROR, source, "异常: " + e.getMessage() + "\n" + stackTrace);
    }
    
    /**
     * 记录日志
     */
    public void log(LogLevel level, String source, String message) {
        // 只有当日志级别大于或等于当前设置级别时才记录
        if (level.ordinal() >= currentLevel.ordinal()) {
            LogEntry entry = new LogEntry(level, source, message, LocalDateTime.now());
            logQueue.offer(entry);
            
            // 同时输出到控制台
            System.out.println(formatLogEntry(entry));
        }
    }
    
    /**
     * 关闭日志记录器
     */
    public void shutdown() {
        running = false;
        logWriterThread.interrupt();
        log(LogLevel.INFO, "Logger", "日志记录器已关闭");
    }
    
    /**
     * 处理日志队列
     */
    private void processLogQueue() {
        try {
            while (running) {
                try {
                    LogEntry entry = logQueue.take(); // 阻塞等待
                    writeLogToFile(entry);
                } catch (InterruptedException e) {
                    if (!running) {
                        break;
                    }
                } catch (IOException e) {
                    System.err.println("写入日志文件时发生错误: " + e.getMessage());
                }
            }
        } finally {
            // 处理剩余的日志
            while (!logQueue.isEmpty()) {
                try {
                    writeLogToFile(logQueue.poll());
                } catch (IOException e) {
                    System.err.println("关闭时写入日志文件发生错误: " + e.getMessage());
                }
            }
        }
    }
    
    /**
     * 将日志写入文件
     */
    private void writeLogToFile(LogEntry entry) throws IOException {
        if (entry == null) {
            return;
        }
        
        // 确保日志目录存在
        File logFile = new File(logFilePath);
        File parentDir = logFile.getParentFile();
        if (parentDir != null && !parentDir.exists()) {
            parentDir.mkdirs();
        }
        
        try (PrintWriter writer = new PrintWriter(new FileWriter(logFilePath, true))) {
            writer.println(formatLogEntry(entry));
        }
    }
    
    /**
     * 格式化日志条目
     */
    private String formatLogEntry(LogEntry entry) {
        return String.format("%s [%s] %s - %s", 
                entry.timestamp.format(formatter),
                entry.level.toString(),
                entry.source,
                entry.message);
    }
    
    /**
     * 获取异常堆栈信息
     */
    private String getStackTraceAsString(Exception e) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : e.getStackTrace()) {
            sb.append("\tat ").append(element.toString()).append("\n");
        }
        return sb.toString();
    }
    
    /**
     * 日志条目内部类
     */
    private static class LogEntry {
        final LogLevel level;
        final String source;
        final String message;
        final LocalDateTime timestamp;
        
        LogEntry(LogLevel level, String source, String message, LocalDateTime timestamp) {
            this.level = level;
            this.source = source;
            this.message = message;
            this.timestamp = timestamp;
        }
    }
} 